Categories
JavaScript Best Practices

JavaScript Best Practices for Writing More Robust Code — Tools and Tests

Spread the love

JavaScript is an easy to learn programming language. It’s easy to write programs that run and does something. However, it’s hard to account for all the uses cases and write robust JavaScript code.

In this article, we’ll look at some tooling and testing best practices for writing robust JavaScript code.

Use TypeScript

TypeScript is a language that’s an extension of JavaScript to provide flexible and optional type checking for JavaScript code.

It builds code into JavaScript so that it can be run on the browser or in the Node.js environment.

The code is checked for type errors before the code is built into the final artifact. This means that data type errors, which would be runtime errors if it weren’t checked by TypeScript are prevented.

This is a big class of errors that are eliminated. The type checking isn’t rigid. It provides many ways to annotate the types of objects and return types of functions.

For instance, we can create interfaces to annotate the types of objects as follows:

interface Pet {
    name: string;
    walk(): void;
}

In the code above, we created an interface to indicate that whatever has the type Pet must have the name string property and a walk method that returns nothing (hence the void return type).

Then we can use that as follows:

const dog: Pet = {
    name: 'joe',
    walk() {
        console.log('walk');
    }
}

In the code above, we have the name string property and the walk method in the dog object, which meets the requirement of the interface.

Therefore, the code will build and run by the TypeScript compiler. We’ll get an error if the types of anything are different from the interface.

Another good feature of TypeScript is the flexibility of the type checking. The types don’t have to be fixed, they can be flexible and dynamic as well.

For instance, we can create nullable types as follows:

interface Pet {
    name: string;
    walk?(): void;
}

In the code above, the walk method has been made optional with the ? after the method name. Now we can omit it in any object that has type Pet .

We can also create union types of multiple types as follows:

interface Pet {
    name: string;
    walk(): void;
}

interface Animal {
    breed: string;
}

const dog: Pet | Animal = {
    name: 'joe',
    breed: 'labrador',
    walk(){}
}

In the code above, we have the Pet | Animal type, which consists of the members of the Pet and Animal types combined together.

Therefore, our dog object can have any member from each interface included in it.

Also, we don’t have to specify the types of an object directly. If we already have an object in our code and we want another object to have the same data type as that one, we can use the typeof operator as follows to specify the type:

const cat = {
    name: 'james'
}

const dog: typeof cat = {
    name: 'joe'
}

In the code above, we specified the data type of the dog object to be the same as the data type for cat with the typeof dog expression. This way, we don’t have to specify any types directly.

TypeScript has many more features that can help us write more solid JavaScript code by preventing data type errors that are otherwise caught at runtime.

This is especially important with big apps where there’s more chance of these errors happening.

Therefore, we should consider using TypeScript for writing more robust JavaScript code.

Photo by Jerry Wang on Unsplash

Write Tests

We should write automated tests to check for regressions in our code so that we can have peace of mind when changing code and all the automated tests pass.

It’s easy to write automated tests with the Jest test runner, which has many features to let us write and run tests for both front and back end JavaScript apps.

For instance, we can write a simple function with unit test as follows:

math.js :

const multiply = (a, b) => {
  return a * b;
}
module.exports = {
  multiply
};

math.test.js :

const math = require('./math');

test('multiplies 1 * 2 to equal 2', () => {
  expect(math.multiply(1, 2)).toBe(2);
});

In the code above, the math.js module has the function multiply that we want to test.

Then in math.test.js , we added our test for testing the multiply function exported by math.js .

The file names are the convention for Jest tests, where we have the name of the production code file corresponds with the name of the test file.

Then when we run Jest, this test will run and should pass because 1 times 2 is 2.

If we write unit tests for every part of our app then it’s easy to know whether our app is still working properly.

Conclusion

TypeScript is probably the best type checker for JavaScript. It’s a natural extension of JavaScript to add type annotations and checking to our JavaScript code.

Writing automated tests is always a good idea so that we can check that our code is working properly after we make changes to it.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *